﻿using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using EFT.HealthSystem;
using EFT.Trainer.Configuration;
using EFT.Trainer.Extensions;
using EFT.Trainer.Properties;
using EFT.Trainer.UI;
using JetBrains.Annotations;
using UnityEngine;

#nullable enable

namespace EFT.Trainer.Features;

[UsedImplicitly]
internal class Hits : ToggleFeature
{
	public override string Name => Strings.FeatureHitsName;
	public override string Description => Strings.FeatureHitsDescription;

	public override bool Enabled { get; set; } = false;

	[ConfigurationProperty(Order = 10)]
	public Color HitMarkerColor { get; set; } = new(225f / 255f, 66f / 255f, 33f / 255f, 1.0f);

	[ConfigurationProperty(Order = 11)]
	public Color ArmorDamageColor { get; set; } = new(0.0f, 126f / 255f, 1.0f, 1.0f);

	[ConfigurationProperty(Order = 12)]
	public Color HealthDamageColor { get; set; } = new(1.0f, 33f / 255f, 33f / 255f, 1.0f);

	[ConfigurationProperty(Order = 20)]
	public float DisplayTime { get; set; } = 2f;

	[ConfigurationProperty(Order = 21)]
	public float FadeOutTime { get; set; } = 1f;

	[ConfigurationProperty(Order = 30)]
	public bool ShowHitMarker { get; set; } = true;

	[ConfigurationProperty(Order = 31)]
	public bool ShowArmorDamage { get; set; } = true;

	[ConfigurationProperty(Order = 32)]
	public bool ShowHealthDamage { get; set; } = true;


	internal class HitMarker(DamageInfoStruct damageInfo)
	{
		public float ElapsedTime { get; set; } = 0.0f;
		public DamageInfoStruct DamageInfo { get; set; } = damageInfo;
		public bool IsTaggedForDeletion { get; set; } = false;
	}

	private static readonly HashSet<HitMarker> _hitMarkers = [];

#pragma warning disable IDE0060
	[UsedImplicitly]
	[SuppressMessage("ReSharper", "InconsistentNaming")]
	protected static void ApplyDamagePostfix(EBodyPart bodyPart, float damage, DamageInfoStruct damageInfo, ActiveHealthController? __instance)
	{
		var feature = FeatureFactory.GetFeature<Hits>();
		if (feature == null || !feature.Enabled)
			return;

		if (__instance == null)
			return;

		var victim = __instance.Player;
		if (victim == null || victim.IsYourPlayer)
			return;

		var shooter = damageInfo.Player?.iPlayer;
		if (shooter is not { IsYourPlayer: true })
			return;

		var marker = new HitMarker(damageInfo);
		_hitMarkers.Add(marker);
	}
#pragma warning restore IDE0060

	protected override void OnGUIWhenEnabled()
	{
		var camera = GameState.Current?.Camera;
		if (camera == null)
			return;

		foreach (var marker in _hitMarkers)
		{
			var damageInfo = marker.DamageInfo;
			marker.ElapsedTime += Time.deltaTime;

			if (damageInfo.Weapon == null || marker.ElapsedTime >= DisplayTime + FadeOutTime)
			{
				marker.IsTaggedForDeletion = true;
				continue;
			}

			var alpha = marker.ElapsedTime > DisplayTime && FadeOutTime > 0f ? (FadeOutTime - marker.ElapsedTime + DisplayTime) / FadeOutTime : 1f;
			var armorDamage = Mathf.Round(damageInfo.ArmorDamage);
			var damage = Mathf.Round(damageInfo.Damage);
			var hitPoint = damageInfo.HitPoint;
			var screenHitPoint = camera.WorldPointToScreenPoint(hitPoint);

			if (ShowHitMarker)
			{
				var radius = 16f + marker.ElapsedTime * 2;
				Render.DrawCircle(screenHitPoint, radius, HitMarkerColor.SetAlpha(alpha), 2.98f, 32);
			}

			var offset = 0f;
			if (armorDamage > 0 && ShowArmorDamage)
			{
				offset = 10f;
				Render.DrawString(new Vector2(screenHitPoint.x, screenHitPoint.y - offset), $"{armorDamage}", ArmorDamageColor.SetAlpha(alpha));
			}

			if (damage > 0 && ShowHealthDamage)
				Render.DrawString(new Vector2(screenHitPoint.x, screenHitPoint.y + offset), $"{damage}", HealthDamageColor.SetAlpha(alpha));
		}

		_hitMarkers.RemoveWhere(m => m.IsTaggedForDeletion);
	}

	protected override void UpdateWhenEnabled()
	{
		var player = GameState.Current?.LocalPlayer;
		if (!player.IsValid())
			return;

		HarmonyPatchOnce(harmony =>
		{
			HarmonyPostfix(harmony, typeof(ActiveHealthController), nameof(ActiveHealthController.ApplyDamage), nameof(ApplyDamagePostfix));
		});
	}
}
